/*
 * There were shamelessly copied from http://www.theserverside.net/tt/articles/showarticle.tss?id=ShellExtensions
 * and then modified to run on W64...
 **/
namespace gisgeb.comserver
{
    using System;
    using System.Runtime.InteropServices;

    // Make these constants
    internal enum Miim : uint
    {
        State = 0x00000001,
        ID = 0x00000002,
        Submenu = 0x00000004,
        Checkmarks = 0x00000008,
        Type = 0x00000010,
        Data = 0x00000020,
        String = 0x00000040,
        Bitmap = 0x00000080,
        Ftype = 0x00000100
    }

    internal enum Mf : uint
    {
        Insert = 0x00000000,
        Change = 0x00000080,
        Append = 0x00000100,
        Delete = 0x00000200,
        Remove = 0x00001000,
        Bycommand = 0x00000000,
        Byposition = 0x00000400,
        Separator = 0x00000800,
        Enabled = 0x00000000,
        Grayed = 0x00000001,
        Disabled = 0x00000002,
        Unchecked = 0x00000000,
        Checked = 0x00000008,
        Usecheckbitmaps = 0x00000200,
        String = 0x00000000,
        Bitmap = 0x00000004,
        Ownerdraw = 0x00000100,
        Popup = 0x00000010,
        Menubarbreak = 0x00000020,
        Menubreak = 0x00000040,
        Unhilite = 0x00000000,
        Hilite = 0x00000080,
        Default = 0x00001000,
        Sysmenu = 0x00002000,
        Help = 0x00004000,
        Rightjustify = 0x00004000,
        Mouseselect = 0x00008000
    }

    internal enum Mfs : uint
    {
        Grayed = 0x00000003,
        Disabled = Grayed,
        Checked = Mf.Checked,
        Hilite = Mf.Hilite,
        Enabled = Mf.Enabled,
        Unchecked = Mf.Unchecked,
        Unhilite = Mf.Unhilite,
        Default = Mf.Default,
        Mask = 0x0000108B,
        HotTrackDrawn = 0x10000000,
        Cachedbmp = 0x20000000,
        Bottomgapdrop = 0x40000000,
        Topgapdrop = 0x80000000,
        Gapdrop = 0xC0000000
    }

    internal enum Clipformat : uint
    {
        CfText = 1,
        CfBitmap = 2,
        CfMetafilepict = 3,
        CfSylk = 4,
        CfDif = 5,
        CfTiff = 6,
        CfOemtext = 7,
        CfDib = 8,
        CfPalette = 9,
        CfPendata = 10,
        CfRiff = 11,
        CfWave = 12,
        CfUnicodetext = 13,
        CfEnhmetafile = 14,
        CfHdrop = 15,
        CfLocale = 16,
        CfMax = 17,

        CfOwnerdisplay = 0x0080,
        CfDsptext = 0x0081,
        CfDspbitmap = 0x0082,
        CfDspmetafilepict = 0x0083,
        CfDspenhmetafile = 0x008E,

        CfPrivatefirst = 0x0200,
        CfPrivatelast = 0x02FF,

        CfGdiobjfirst = 0x0300,
        CfGdiobjlast = 0x03FF
    }

    internal enum Dvaspect : uint
    {
        DvaspectContent = 1,
        DvaspectThumbnail = 2,
        DvaspectIcon = 4,
        DvaspectDocprint = 8
    }

    internal enum Tymed : uint
    {
        TymedHglobal = 1,
        TymedFile = 2,
        TymedIstream = 4,
        TymedIstorage = 8,
        TymedGdi = 16,
        TymedMfpict = 32,
        TymedEnhmf = 64,
        TymedNull = 0
    }

    internal enum Cmf : uint
    {
        CmfNormal = 0x00000000,
        CmfDefaultonly = 0x00000001,
        CmfVerbsonly = 0x00000002,
        CmfExplore = 0x00000004,
        CmfNoverbs = 0x00000008,
        CmfCanrename = 0x00000010,
        CmfNodefault = 0x00000020,
        CmfIncludestatic = 0x00000040,
        CmfReserved = 0xffff0000 // View specific
    }

    // GetCommandString uFlags
    internal enum Gcs : uint
    {
        VerbA = 0x00000000, // canonical verb
        HelpTextA = 0x00000001, // help text (for status bar)
        Validatea = 0x00000002, // validate command exists
        Verbw = 0x00000004, // canonical verb (unicode)
        Helptextw = 0x00000005, // help text (unicode version)
        Validatew = 0x00000006, // validate command exists (unicode)
        Unicode = 0x00000004, // for bit testing - Unicode string
        Verb = VerbA,
        Helptext = HelpTextA,
        Validate = Validatea
    }

    [StructLayout(LayoutKind.Sequential)]
    internal class StartupInfo
    {
        internal int cb;

        internal String lpReserved;

        internal String lpDesktop;

        internal String lpTitle;

        internal int dwX;

        internal int dwY;

        internal int dwXSize;

        internal int dwYSize;

        internal int dwXCountChars;

        internal int dwYCountChars;

        internal int dwFillAttribute;

        internal int dwFlags;

        internal UInt16 wShowWindow;

        internal UInt16 cbReserved2;

        internal Byte lpReserved2;

        internal int hStdInput;

        internal int hStdOutput;

        internal int hStdError;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal class ProcessInformation
    {
        internal int hProcess;

        internal int hThread;

        internal int dwProcessId;

        internal int dwThreadId;
    }

   
    [StructLayout(LayoutKind.Sequential)]
    internal struct Menuiteminfo
    {
        internal uint cbSize;

        internal uint fMask;

        internal uint fType;

        internal uint fState;

        internal uint wID;

        internal IntPtr /*HMENU*/ hSubMenu;

        internal IntPtr /*HBITMAP*/ hbmpChecked;

        internal IntPtr /*HBITMAP*/ hbmpUnchecked;

        internal IntPtr /*ULONG_PTR*/ dwItemData;

        internal String dwTypeData;

        internal uint cch;

        internal IntPtr /*HBITMAP*/ hbmpItem;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct Formatetc
    {
        internal Clipformat cfFormat;

        internal uint ptd;

        internal Dvaspect dwAspect;

        internal int lindex;

        internal Tymed tymed;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct Stgmedium
    {
        internal uint tymed;

        internal uint hGlobal;

        internal uint pUnkForRelease;
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    internal struct Invokecommandinfo
    {
        //NOTE: When SEE_MASK_HMONITOR is set, hIcon is treated as hMonitor
        internal int cbSize; // sizeof(CMINVOKECOMMANDINFO)

        internal int fMask; // any combination of CMIC_MASK_*

        internal IntPtr wnd; // might be NULL (indicating no owner window)
        
        internal int verb;

        [MarshalAs(UnmanagedType.LPStr)]
        internal string parameters; // might be NULL (indicating no parameter)

        [MarshalAs(UnmanagedType.LPStr)]
        internal string directory; // might be NULL (indicating no specific directory)

        internal int Show; // one of SW_ values for ShowWindow() API

        internal uint HotKey;

        internal IntPtr hIcon;
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
     GuidAttribute("0000010e-0000-0000-C000-000000000046")]
    internal interface IDataObject
    {
        [PreserveSig]
        int GetData(ref Formatetc a, ref Stgmedium b);

        [PreserveSig]
        void GetDataHere(int a, ref Stgmedium b);

        [PreserveSig]
        int QueryGetData(int a);

        [PreserveSig]
        int GetCanonicalFormatEtc(int a, ref int b);

        [PreserveSig]
        int SetData(int a, int b, int c);

        [PreserveSig]
        int EnumFormatEtc(uint a, ref Object b);

        [PreserveSig]
        int DAdvise(int a, uint b, Object c, ref uint d);

        [PreserveSig]
        int DUnadvise(uint a);

        [PreserveSig]
        int EnumDAdvise(ref Object a);
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
     GuidAttribute("000214e8-0000-0000-c000-000000000046")]
    internal interface IShellExtInit
    {
        void Initialize(IntPtr pidlFolder, IntPtr lpdobj, uint /*HKEY*/ hKeyProgID);
    }

    [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown),
     GuidAttribute("000214e4-0000-0000-c000-000000000046")]
    internal interface IContextMenu
    {
        // IContextMenu methods
        [PreserveSig]
        int QueryContextMenu(IntPtr hmenu, uint iMenu, int idCmdFirst, int idCmdLast, uint uFlags);

        void InvokeCommand(IntPtr pici);

        void GetCommandString(int idcmd, uint uflags, int reserved, IntPtr commandstring, int cch);
    }

    /// <summary>
    /// Most of this is not used... Someday I'll find some folks willing to publish some Interop-Code with me...
    /// That is the day this will come handy.
    /// <see cref="http://msdn.microsoft.com/en-us/library/ms691242%28VS.85%29.aspx"/>
    /// </summary>
    public static class HResultHelper
    {
        /// <summary>
        /// Creates an HRESULT value from its component pieces.
        /// <see cref="http://msdn.microsoft.com/en-us/library/ms694497%28VS.85%29.aspx"/>
        /// <see cref="http://msdn.microsoft.com/en-us/library/ms819773.aspx"/>
        /// </summary>
        /// <param name="severety">The severity.
        ///  0: Success,
        ///  1: Information,
        ///  2: Warning,
        ///  3: Error
        /// </param>
        /// <param name="faculty">The facility.
        ///  i.e. Use 0 for NULL or 7 for Win32...</param>
        /// <param name="code">The code.</param>
        /// <returns></returns>
        public static int MakeHresult(Severity severety, Faculty faculty, int code)
        {
            return ((int)severety << 31) + ((int)faculty << 16) + (code);
        }  
     
        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/ms687197%28VS.85%29.aspx
        /// </summary>
        /// <param name="hresult"></param>
        /// <returns></returns>
        public static bool Succeeded(long hresult)
        {
            return hresult > 0;
        }

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/ms693474%28VS.85%29.aspx
        /// </summary>
        /// <param name="hresult"></param>
        /// <returns></returns>
        public static bool Failed(long hresult)
        {
            return !Succeeded(hresult);
        }

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/ms693761%28VS.85%29.aspx
        /// </summary>
        /// <param name="hresult"></param>
        /// <returns></returns>
        public static int GetSeverety(long hresult)
        {
            return (int)((hresult >> 31) & 0x1);
        }

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/ms680579%28VS.85%29.aspx
        /// </summary>
        /// <param name="hresult"></param>
        /// <returns></returns>
        public static int GetFaculty(long hresult)
        {
            return (int)((hresult >> 16) & 0x1fff);
        }

        /// <summary>
        /// http://msdn.microsoft.com/en-us/library/ms679761%28VS.85%29.aspx
        /// </summary>
        /// <param name="hresult"></param>
        /// <returns></returns>
        public static int GetCode(long hresult)
        {
            return (int) (hresult & 0xFFFF);
        }

        // Some well known codes, see http://msdn.microsoft.com/en-us/library/ms819773.aspx for more.
        public static int ErrorCodeSuccess = 0;

        public static int ErrorCodeFileNotFound = 2;

        public static int ErrorCodeInvalidParameter = 87;

        public static int ErrorCodeOutOfMemory = 14;

        // Some well known hresults...
        public static int HResultOk = MakeHresult(Severity.Success, Faculty.Null, 0);

        public enum Severity 
        {
            Success = 0,
            Information = 1,
            Warning = 2,
            Error = 3
        }

        public enum Faculty 
        {
            Null = 0,
            Win32 = 7,
        }
    }
}